<!--
  页面名称: 测试页面
  路由路径: /humanmachine/test
  Dify App URL: http://192.168.0.170/app/b679e219-3631-48d3-bdd0-37ad88d06801/develop
  Dify API Key: app-us3IVdDty5Xgw0O6Geft4qdu
-->
<template>
  <div class="test-chat">
    <Layout style="height: calc(100vh - 120px)">
      <LayoutContent :style="contentStyle">
        <div class="chat-container">
          <div ref="messagesContainer" class="messages-container">
            <div 
              v-for="(message, index) in messages" 
              :key="index" 
              :class="['message-item', message.role]"
            >
              <div class="message-avatar">
                <span v-if="message.role === 'user'">{{ UserIcon }}</span>
                <span v-else>{{ RobotIcon }}</span>
              </div>
              <div class="message-content">
                <div class="message-text" v-html="formatMessage(message.content)"></div>
                <div class="message-time">{{ formatTime(message.time) }}</div>
              </div>
            </div>
            <div v-if="loading" class="message-item assistant">
              <div class="message-avatar">
                <span>{{ RobotIcon }}</span>
              </div>
              <div class="message-content">
                <div class="message-text">
                  <Spin size="small" />
                  <span style="margin-left: 8px;">正在思考中...</span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </LayoutContent>
      <LayoutFooter :style="footerStyle">
        <div class="input-container flex-row-center">
          <Input
            v-model:value="inputMessage"
            placeholder="请输入您的问题..."
            :disabled="loading"
            @pressEnter="handleSend"
            style="flex: 1; min-width: 120px; margin-right: 8px;"
          />
          <Button 
            type="primary" 
            @click="handleSend"
            :loading="loading"
            :disabled="!inputMessage.trim()"
            style="margin-right: 8px;"
          >
            发送
          </Button>
          <Button 
            @click="handleStop"
            :disabled="!loading"
            style="margin-right: 8px;"
          >
            停止响应
          </Button>
          <Button
            type="default"
            @click="handleNewConversation"
            :disabled="loading"
            style="margin-left:auto;"
          >
            开启新对话
          </Button>
        </div>
      </LayoutFooter>
    </Layout>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, nextTick } from 'vue';
import {
  Layout,
  LayoutContent,
  LayoutFooter,
  Input,
  Button,
  Spin,
  message,
} from 'ant-design-vue';
const UserIcon = '👤';
const RobotIcon = '🤖';
import { testChat } from '#/api/man-machine/test';

const contentStyle = {
  background: '#f0f2f5',
  padding: '24px',
  overflow: 'auto',
};

const footerStyle = {
  background: '#fff',
  padding: '16px 24px',
  borderTop: '1px solid #e8e8e8',
};

interface Message {
  role: 'user' | 'assistant';
  content: string;
  time: Date;
}

const messages = ref<Message[]>([]);
const inputMessage = ref('');
const loading = ref(false);
const conversationId = ref('');
const messagesContainer = ref<HTMLDivElement | null>(null);
const typingTimer = ref<NodeJS.Timeout | null>(null);
const fullAnswerBuffer = ref<{ index: number; text: string } | null>(null);

const handleSend = async () => {
  if (!inputMessage.value.trim() || loading.value) {
    return;
  }

  const userMessage = inputMessage.value.trim();
  inputMessage.value = '';
  await nextTick();

  messages.value.push({
    role: 'user',
    content: userMessage,
    time: new Date(),
  });

  scrollToBottom();

  const aiMessageIndex = messages.value.length;
  messages.value.push({ role: 'assistant', content: '', time: new Date() });

  loading.value = true;

  try {
    const result = await testChat({
      query: userMessage,
      conversation_id: conversationId.value || undefined,
      user: 'user',
      onMessage: (fullMessage: string) => {
        fullAnswerBuffer.value = { index: aiMessageIndex, text: fullMessage };
        if (typingTimer.value) {
          clearInterval(typingTimer.value as any);
          typingTimer.value = null;
        }
        startTypingEffect(aiMessageIndex, fullMessage);
      },
      onError: (error: Error) => {
        console.error('Chat error:', error);
        // 显示友好的错误消息
        const errorMsg = error.message || '发送消息失败，请稍后重试';
        message.error({
          content: errorMsg,
          duration: 5, // 显示5秒
        });
        // 如果有原始错误消息，也在控制台输出
        if ((error as any).originalMessage) {
          console.error('原始错误信息:', (error as any).originalMessage);
        }
        loading.value = false;
        if (typingTimer.value) {
          clearInterval(typingTimer.value as any);
          typingTimer.value = null;
        }
        // 如果AI消息已创建但内容为空，显示错误提示
        if (messages.value[aiMessageIndex] && !messages.value[aiMessageIndex].content) {
          messages.value[aiMessageIndex].content = `❌ 错误: ${errorMsg}`;
        }
      },
      onComplete: () => {
        console.log('流式响应完成');
        loading.value = false;
        // 确保完整消息被保存
        if (fullAnswerBuffer.value && messages.value[aiMessageIndex]) {
          messages.value[aiMessageIndex].content = fullAnswerBuffer.value.text;
        }
        // 停止打字效果，显示完整内容
        if (typingTimer.value) {
          clearInterval(typingTimer.value as any);
          typingTimer.value = null;
        }
        scrollToBottom();
      },
    });

    if (result && result.conversation_id && !conversationId.value) {
      conversationId.value = result.conversation_id;
    }

    if (result && result.answer && messages.value[aiMessageIndex]) {
      if (!messages.value[aiMessageIndex].content) {
        messages.value[aiMessageIndex].content = result.answer;
      }
    }

    if (messages.value[aiMessageIndex]) {
      messages.value[aiMessageIndex].time = new Date();
      if (!messages.value[aiMessageIndex].content) {
        message.warning('未收到回复，请检查Dify服务或查看控制台日志');
      }
    }

    if (typingTimer.value) {
      clearInterval(typingTimer.value as any);
      typingTimer.value = null;
    }
    if (fullAnswerBuffer.value && messages.value[aiMessageIndex]) {
      messages.value[aiMessageIndex].content = fullAnswerBuffer.value.text;
    } else if (result && result.answer && messages.value[aiMessageIndex]) {
      messages.value[aiMessageIndex].content = result.answer;
    }
  } catch (error) {
    console.error('Send message error:', error);
    message.error('发送消息失败，请重试');
    messages.value.pop();
    if (typingTimer.value) {
      clearInterval(typingTimer.value as any);
      typingTimer.value = null;
    }
  } finally {
    loading.value = false;
    if (typingTimer.value) {
      clearInterval(typingTimer.value as any);
      typingTimer.value = null;
    }
    if (inputMessage.value) {
      inputMessage.value = '';
    }
    scrollToBottom();
  }
};


const handleStop = () => {
  if (typingTimer.value) {
    clearInterval(typingTimer.value as any);
    typingTimer.value = null;
  }
  loading.value = false;
};

const handleNewConversation = () => {
  if (typingTimer.value) {
    clearInterval(typingTimer.value as any);
    typingTimer.value = null;
  }
  messages.value = [];
  conversationId.value = '';
  inputMessage.value = '';
  fullAnswerBuffer.value = null;
  messages.value.push({
    role: 'assistant',
    content: '您好！有什么可以帮助您的吗？',
    time: new Date(),
  });
};

const startTypingEffect = (messageIndex: number, fullText: string) => {
  if (typingTimer.value) clearInterval(typingTimer.value as any);
  if (!messages.value[messageIndex]) return;
  let currentLength = messages.value[messageIndex].content.length;
  const targetLength = fullText.length;
  if (targetLength <= currentLength) {
    messages.value[messageIndex].content = fullText;
    nextTick(() => scrollToBottom());
    return;
  }
  const speed = 30;
  typingTimer.value = setInterval(() => {
    if (!messages.value[messageIndex]) {
      if (typingTimer.value) {
        clearInterval(typingTimer.value as any);
        typingTimer.value = null;
      }
      return;
    }
    const latestFullText = fullAnswerBuffer.value?.text || fullText;
    if (currentLength >= latestFullText.length) {
      if (typingTimer.value) {
        clearInterval(typingTimer.value as any);
        typingTimer.value = null;
      }
      messages.value[messageIndex].content = latestFullText;
      loading.value = false;
      nextTick(() => scrollToBottom());
      return;
    }
    const charsPerUpdate = 2;
    const nextLength = Math.min(currentLength + charsPerUpdate, latestFullText.length);
    messages.value[messageIndex].content = latestFullText.substring(0, nextLength);
    currentLength = nextLength;
    nextTick(() => scrollToBottom());
  }, speed);
};

const scrollToBottom = () => {
  nextTick(() => {
    if (messagesContainer.value) {
      messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
    }
  });
};

const formatMessage = (content: string): string => {
  if (!content) return '';
  
  // 先处理 Markdown 表格
  // 匹配 Markdown 表格格式: | 列1 | 列2 | ... |
  const tableRegex = /(\|.+\|\n\|[\s\-:]+\|\n(?:\|.+\|\n?)+)/g;
  let formatted = content.replace(tableRegex, (match) => {
    const lines = match.trim().split('\n').filter(line => line.trim());
    if (lines.length < 2) return match; // 至少需要表头和分隔行
    
    // 解析表头
    const headerLine = lines[0];
    if (!headerLine) return match;
    const headers = headerLine.split('|').map(h => h.trim()).filter(h => h);
    
    // 解析数据行（跳过分隔行）
    const dataLines = lines.slice(2);
    const rows = dataLines.map(line => {
      return line.split('|').map(cell => cell.trim()).filter((_, index, arr) => {
        // 过滤掉首尾的空元素
        return index > 0 && index < arr.length - 1;
      });
    });
    
    // 构建 HTML 表格
    let htmlTable = '<div class="message-table-wrapper"><table class="message-table"><thead><tr>';
    headers.forEach(header => {
      htmlTable += `<th>${header}</th>`;
    });
    htmlTable += '</tr></thead><tbody>';
    
    rows.forEach(row => {
      htmlTable += '<tr>';
      headers.forEach((_, index) => {
        const cellContent = row[index] || '';
        htmlTable += `<td>${cellContent}</td>`;
      });
      htmlTable += '</tr>';
    });
    
    htmlTable += '</tbody></table></div>';
    return htmlTable;
  });
  
  // 处理其他 Markdown 格式
  formatted = formatted
    .replace(/\n/g, '<br>')
    .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
    .replace(/\*(.+?)\*/g, '<em>$1</em>')
    .replace(/`(.+?)`/g, '<code>$1</code>');
  
  return formatted;
};

const formatTime = (date: Date | undefined): string => {
  if (!date) return '';
  const d = new Date(date);
  return d.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
};

onMounted(() => {
  messages.value.push({
    role: 'assistant',
    content: '您好！有什么可以帮助您的吗？',
    time: new Date(),
  });
});

onUnmounted(() => {
  if (typingTimer.value) {
    clearInterval(typingTimer.value as any);
    typingTimer.value = null;
  }
});
</script>

<style scoped>
.test-chat { height: 100%; }
.chat-container { height: 100%; background: #fff; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; }
.messages-container { flex: 1; overflow-y: auto; padding: 24px; min-height: 400px; }
.message-item { display: flex; margin-bottom: 24px; animation: fadeIn 0.3s; }
.message-item.user { justify-content: flex-end; }
.message-item.assistant { justify-content: flex-start; }
.message-avatar { width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; margin: 0 12px; }
.message-item.user .message-avatar { background: #1890ff; color: #fff; order: 2; }
.message-item.assistant .message-avatar { background: #f0f0f0; color: #666; }
.message-content { max-width: 70%; display: flex; flex-direction: column; }
.message-item.user .message-content { align-items: flex-end; }
.message-item.assistant .message-content { align-items: flex-start; }
.message-text { padding: 12px 16px; border-radius: 12px; line-height: 1.6; word-wrap: break-word; }
.message-item.user .message-text { background: #1890ff; color: #fff; border-bottom-right-radius: 4px; }
.message-item.assistant .message-text { background: #f0f0f0; color: #333; border-bottom-left-radius: 4px; }
.message-time { font-size: 12px; color: #999; margin-top: 4px; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
.flex-row-center {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  width: 100%;
}
.message-table-wrapper {
  overflow-x: auto;
  margin: 12px 0;
  max-width: 100%;
}
.message-table {
  width: 100%;
  border-collapse: collapse;
  border-spacing: 0;
  font-size: 14px;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  border-radius: 4px;
  overflow: hidden;
}
.message-table thead {
  background: #f5f5f5;
}
.message-table th {
  padding: 12px 16px;
  text-align: left;
  font-weight: 600;
  color: #333;
  border-bottom: 2px solid #e8e8e8;
  white-space: nowrap;
}
.message-table td {
  padding: 12px 16px;
  border-bottom: 1px solid #f0f0f0;
  color: #666;
}
.message-table tbody tr:hover {
  background: #fafafa;
}
.message-table tbody tr:last-child td {
  border-bottom: none;
}
.message-item.assistant .message-table-wrapper {
  max-width: 100%;
}
.message-item.user .message-table-wrapper {
  max-width: 100%;
}
</style>
